JVM = function() {
	this.classes = new Array();
	this.methods = new Array();
	this.stack = new Array();
}
JVM.prototype.declareClass = function(javaClass) {
	this.classes[javaClass.name] = javaClass;
	return javaClass;
}
JVM.prototype.po = function() {
	return this.stack.pop();
}
JVM.prototype.pu = function(a) {
	this.stack.push(a);
}

JVM.prototype.start = function(mainClass,args) {
	mainClass = mainClass.replace(/\./g,'/');
	var myClass = this.getClasse(mainClass);
	if(myClass == undefined) 
		throw mainClass+' not found';
	myClass.methods['main([Ljava/lang/String;)V'].invoke(args);
}

JVM.prototype.getClasse = function(name) {
	if(this.classes[name] !== undefined)
		return this.classes[name];
	else {
		var filename = "/classes/"+name.replace(/\./g,'/')+".class.js";
		document.write('<script type="text/javascript" src="' + encodeURI(filename) + '"></script>');
		/*
		var fileref=document.createElement('script');
	    fileref.setAttribute("type","text/javascript");
	    fileref.setAttribute("src", filename);
	    fileref.onreadystatechange= function () {
      	if (this.readyState == 'complete') resumeVM();
	   }
	   script.onload= helper;
	    document.getElementsByTagName("head")[0].appendChild(fileref);
	    return this.classes[name];

	    var http = false;
	    if(navigator.appName == "Microsoft Internet Explorer") {
	      http = new ActiveXObject("Microsoft.XMLHTTP");
	    } else {
	      http = new XMLHttpRequest();
	    }
	    http.open("GET", filename,false);
	    http.onreadystatechange=function() {
	      if(http.readyState == 4) {
	    	eval(http.responseText);
	      }
	    }
	    http.send(null);
	    eval(http.responseText);
	*/
	    return this.classes[name];

	}
}

vm = new JVM();

JavaClass = function(name) {
	this.name = name;
	this.methods = new Array();
	this.fields = new Array();
}
JavaClass.prototype.toString = function() {
	return this.name;
}
JavaClass.prototype.declareMethod = function(method) {
	this.methods[method.desc] = method;
	return method;
}

JavaObject = function(javaClass) {
	this.javaClass = javaClass;
	this.fields = new Array();
}
JavaObject.prototype.toString = function() {
	return "JavaObject : "+this.javaClass;
}

JavaMethod = function(desc) {
	this.desc = desc;
	this.annotations = new Array();
	this.paramAnnotations = new Array();
	this.invoke = function() {
		throw 'method '+desc+' invoke method should be overrided !';
	}
}
JavaMethod.prototype.toString = function() {
	return "JavaMethod : "+this.desc;
}

  escapeHTML = function(s) {
    return s
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
  };


with(vm.declareClass(new JavaClass('MySystemOutClass'))) {
	with(declareMethod(new JavaMethod('println(I)V'))) {
		invoke=function() {
			document.getElementById('console').innerHTML += escapeHTML(""+vm.po())+"<br>";
			vm.po(); // this
		}
	}
	with(declareMethod(new JavaMethod('println(Ljava/lang/String;)V'))) {
		invoke=function() {
			document.getElementById('console').innerHTML += escapeHTML(""+vm.po())+"<br>";
			vm.po(); // this
		}
	}
}

with(vm.declareClass(new JavaClass('java/lang/System'))) {
	fields['out'] = new JavaObject(vm.classes['MySystemOutClass']);
}

with(vm.declareClass(new JavaClass('java/lang/Object'))) {
	with(declareMethod(new JavaMethod('<init>()V'))) {
		invoke = function() {
			alert(vm.po());
	//		vm.po();
		}
	}
}


with(vm.declareClass(new JavaClass('java/lang/Class'))) {
	with(declareMethod(new JavaMethod('forName(Ljava/lang/String;)Ljava/lang/Class;'))) {
		invoke = function() {
			var name = vm.po();
			jObj = new JavaObject(vm.getClasse('java/lang/Class'));
			jObj.nativeClass = vm.getClasse(name);
			vm.pu(jObj);
		}
	}
}

